package com.sayice.gomoku.utils;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * 文件上传工具类
 */
public abstract class FileUploadUtils {
    /**
     * 处理文件上传表单
     *
     * @param req     请求
     * @param handler 处理器（需要提供一个名为 "handle" 的方法）
     */
    public static void handleMultiPart(HttpServletRequest req, MultiPartHandler handler) throws InvocationTargetException, IllegalAccessException, FileUploadException, UnsupportedEncodingException {
        for (Method method : handler.getClass().getDeclaredMethods()) {
            if ("handle".equals(method.getName())) {
                String[] paramNames = Arrays.stream(method.getParameters()).map(Parameter::getName).toArray(String[]::new);
                Class<?>[] paramClasses = method.getParameterTypes();
                Object[] arguments = new Object[paramNames.length];
                FileItemFactory fileItemFactory = new DiskFileItemFactory();
                ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
                List<FileItem> list = servletFileUpload.parseRequest(req);
                for (FileItem fileItem : list) {
                    if (fileItem.isFormField()) {
                        for (int i = 0; i < paramNames.length; i++) {
                            if (paramNames[i].equals(fileItem.getFieldName())) {
                                Class<?> paramClass = paramClasses[i];
                                String value = fileItem.getString().trim();
                                if (paramClass == int.class) {
                                    arguments[i] = Integer.parseInt(value);
                                } else if (paramClass == BigDecimal.class) {
                                    arguments[i] = new BigDecimal(value);
                                } else if (paramClass == String.class) {
                                    arguments[i] = new String(value.getBytes(StandardCharsets.ISO_8859_1),
                                            StandardCharsets.UTF_8);
                                    System.out.println(arguments[i]);
                                } else {
                                    throw new RuntimeException("Missing handler for type: " + paramClass);
                                }
                            }
                        }
                    } else {
                        for (int i = 0; i < paramNames.length; i++) {
                            if (paramNames[i].equals(fileItem.getFieldName())) {
                                arguments[i] = fileItem;
                            }
                        }
                    }
                }
                method.setAccessible(true);
                System.out.println(Arrays.toString(paramNames));
                System.out.println(Arrays.toString(arguments));
                method.invoke(handler, arguments);
                return;
            }
        }
        throw new RuntimeException("Missing method names \"handle\"");
    }
    
    /**
     * 上传文件
     *
     * @param dirPath  文件夹路径
     * @param file     要上传的文件
     * @param fileName 保存的文件名（含后缀）
     * @return 上传成功返回 true，否则返回 false
     */
    public static boolean upload(String dirPath, FileItem file, String fileName) throws Exception {
        File dir = new File(dirPath);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                System.out.println("创建文件夹 " + dirPath + " 失败！");
                return false;
            }
        }
        File destFile = new File(dirPath + "/" + fileName);
        destFile.delete();
        file.write(destFile);
        System.out.println("上传文件成功: " + fileName + " -> " + dirPath);
        return true;
    }
    
    /**
     * 文件上传表单处理器
     */
    public interface MultiPartHandler {
    }
}
